package sve;

import java.util.HashMap;

import sve.Evaluator.Range;

import xadd.XADD;
import xadd.XADD.ArithExpr;
import xadd.XADD.DoubleExpr;

public class Evaluator {

	public static class Range {
		public Range(String v, double s, double st, double e) {
			var = v;
			start = s;
			step = st;
			end = e;
		}

		public String var;
		public double start;
		public double step;
		public double end;
	}

	public void drawGraph(Pair<Integer, XADD> p, String... vars) {
		for (String s : vars) {
			// _buffer.getContext().getGraph(_buffer.getVar(s)).launchViewer();
		}
		if (p != null)
			p.getValue().getGraph(p.getKey()).launchViewer();
	}

	public static double[][] generateEvaluationDouble(Pair<Integer, XADD> p, String var, double start, double step,
			double end) {
		return generateEvaluationDouble(p, null, null, var, start, step, end);
	}

	public static Pair<double[][], double[][]> generateEvaluationDouble(Pair<Integer, XADD> p, String var1,
			double start1, double step1, double end1, String var2, double start2, double step2, double end2) {
		return generateEvaluationDouble(p, null, null, var1, start1, step1, end1, var2, start2, step2, end2);
	}

	public static double[][] generateEvaluationDouble(Pair<Integer, XADD> p, String[] vars, double[] vals, String var,
			double start, double step, double end) {
		HashMap<String, ArithExpr> subst = SVE.getSubstitutionList(vars, vals);
		return generateEvaluationDouble(p.getValue(), p.getKey(), subst, var, start, step, end);
	}

	public static Pair<double[][], double[][]> generateEvaluationDouble(Pair<Integer, XADD> p, String[] vars,
			double[] vals, String var1, double start1, double step1, double end1, String var2, double start2,
			double step2, double end2) {
		HashMap<String, ArithExpr> subst = SVE.getSubstitutionList(vars, vals);
		return generateEvaluationDouble(p.getValue(), p.getKey(), subst, var1, start1, step1, end1, var2, start2,
				step2, end2);
	}

	public static double[][] generateEvaluationDouble(XADD x, int id, String var, String[] vars, double[] vals,
			double start, double step, double end) {
		return generateEvaluationDouble(new Pair<Integer, XADD>(id, x), vars, vals, var, start, step, end);
	}

	public static double[][] generateEvaluationDouble(XADD x, int id, String var, double start, double step, double end) {
		return generateEvaluationDouble(new Pair<Integer, XADD>(id, x), null, null, var, start, step, end);
	}

	// public double[][] generateEvaluationDouble(String var, int start, double step, int end) {
	// return generateEvaluationDouble(_buffer.getContext(), _buffer.getVar(var), var, null, null, start, step, end);
	// }
	//
	// public double[][] generateEvaluationDouble(String var, String[] vars, double[] vals, int start, double step, int
	// end) {
	// return generateEvaluationDouble(_buffer.getContext(), _buffer.getVar(var), var, vars, vals, start, step, end);
	// }
	//
	// public double[][] generateEvaluationDouble(String node_var, String var, String[] vars, double[] vals, int start,
	// double step, int end) {
	// return generateEvaluationDouble(_buffer.getContext(), _buffer.getVar(node_var), var, vars, vals, start, step,
	// end);
	// }

	private static double[][] generateEvaluationDouble(XADD x, int id, HashMap<String, ArithExpr> subst, String var,
			double start, double step, double end) {
		return generateEvaluationDouble(x, id, subst, new Range(var, start, step, end));
	}

	private static double[][] generateEvaluationDouble(XADD x, int id, HashMap<String, ArithExpr> subst, Range r) {

		int count = (int) ((r.end - r.start) / r.step), idx = 0;
		double[][] d = new double[count][2];
		if (subst != null && subst.size() > 0) {
			id = x.substitute(id, subst);
		}
		HashMap<String, Double> hm = new HashMap<String, Double>();
		HashMap<String, Boolean> bool_assign = new HashMap<String, Boolean>();
		while (idx < count) {
			hm.clear();
			hm.put(r.var, r.start);
			d[idx][0] = r.start;
			XADD newX = new XADD();
			int subId = SVE.getXADD(newX, x.getString(id));
			Double val = newX.evaluate(subId, bool_assign, hm);
			d[idx][1] = Math.max(val == null ? 0 : val, 0);
			// System.out.println(idx + ", " + d[idx][0] + ", " + d[idx][1]);
			idx++;
			r.start = r.start + r.step;
		}

		return d;
	}

	private static Pair<double[][], double[][]> generateEvaluationDouble(XADD x, int id,
			HashMap<String, ArithExpr> subst, String var1, double start1, double step1, double end1, String var2,
			double start2, double step2, double end2) {
		return generateEvaluationDouble(x, id, subst, new Range(var1, start1, step1, end1), new Range(var2, start2,
				step2, end2));
	}

	private static Pair<double[][], double[][]> generateEvaluationDouble(XADD x, int id,
			HashMap<String, ArithExpr> subst, Range r1, Range r2) {

		int count1 = (int) ((r1.end - r1.start) / r1.step), idx1 = 0, count2 = (int) ((r2.end - r2.start) / r2.step), idx2 = 0;
		double[][] d = new double[count1][2];
		double[][] ret = new double[count1][count2];
		if (subst != null && subst.size() > 0) {
			id = x.substitute(id, subst);
		}
		HashMap<String, Double> hm = new HashMap<String, Double>();
		HashMap<String, Boolean> bool_assign = new HashMap<String, Boolean>();
		while (idx1 < count1) {
			double start = r2.start;
			while (idx2 < count2) {
				hm.clear();
				hm.put(r1.var, r1.start);
				d[idx1][0] = r1.start;
				hm.put(r2.var, start);
				d[idx2][1] = start;
				XADD newX = new XADD();
				int subId = SVE.getXADD(newX, x.getString(id));
				Double val = newX.evaluate(subId, bool_assign, hm);
				ret[idx1][idx2] = Math.max(val == null ? 0 : val, 0);
				// System.out.println(idx1 + ", " + idx2 + ", " + d[idx1][0] + ", " + d[idx2][1] + ", " +
				// ret[idx1][idx2]);
				idx2++;
				start = start + r2.step;
			}
			idx1++;
			idx2 = 0;

			r1.start = r1.start + r1.step;
		}
		return new Pair<double[][], double[][]>(d, ret);
	}

	public static Pair<double[][], double[][]> generateEvaluationDouble(Pair<Integer, XADD> p, Range r1, Range r2) {
		return generateEvaluationDouble(p.getValue(), p.getKey(), null, r1, r2);
	}
}
